#include "checks.h"

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>

extern "C" void Cgen_Fatal(const char* file, int line, const char* format, ...)
{
    char buf[256];

    va_list arguments;
    va_start(arguments, format);
    vsprintf(buf, format, arguments);
    va_end(arguments);

    fprintf(stderr, "FATAL: %s(%d): %s\n", file, line, buf);

    abort();
}

void API_Fatal(const char* location, const char* format, ...)
{
    char buf[256];

    va_list arguments;
    va_start(arguments, format);
    vsprintf(buf, format, arguments);
    va_end(arguments);

    fprintf(stderr, "FATAL: %s: %s\n", location, buf);

    abort();
}


void CheckHelper(const char* file,
                               int line,
                               const char* source,
                               bool condition) {
  if (!condition)
    Cgen_Fatal(file, line, "CHECK(%s) failed", source);
}


void CheckEqualsHelper(const char* file, int line,
                                     const char* expected_source, int expected,
                                     const char* value_source, int value) {
  if (expected != value) {
    Cgen_Fatal(file, line,
             "CHECK_EQ(%s, %s) failed\n#   Expected: %i\n#   Found: %i",
             expected_source, value_source, expected, value);
  }
}


void CheckNonEqualsHelper(const char* file,
                                        int line,
                                        const char* unexpected_source,
                                        int unexpected,
                                        const char* value_source,
                                        int value) {
  if (unexpected == value) {
    Cgen_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %i",
             unexpected_source, value_source, value);
  }
}

void CheckEqualsHelper(const char* file,
                                     int line,
                                     const char* expected_source,
                                     const char* expected,
                                     const char* value_source,
                                     const char* value) {
  if (strcmp(expected, value) != 0) {
    Cgen_Fatal(file, line,
             "CHECK_EQ(%s, %s) failed\n#   Expected: %s\n#   Found: %s",
             expected_source, value_source, expected, value);
  }
}

void CheckNonEqualsHelper(const char* file,
                                        int line,
                                        const char* expected_source,
                                        const char* expected,
                                        const char* value_source,
                                        const char* value) {
  if (expected == value ||
      (expected != NULL && value != NULL && strcmp(expected, value) == 0)) {
    Cgen_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %s",
             expected_source, value_source, value);
  }
}


void CheckEqualsHelper(const char* file,
                       int line,
                       const char* expected_source,
                       void* expected,
                       const char* value_source,
                       void* value) {
  if (expected != value) {
    Cgen_Fatal(file, line,
             "CHECK_EQ(%s, %s) failed\n#   Expected: %p\n#   Found: %p",
             expected_source, value_source,
             expected, value);
  }
}


void CheckNonEqualsHelper(const char* file,
                          int line,
                          const char* expected_source,
                          void* expected,
                          const char* value_source,
                          void* value) {
  if (expected == value) {
    Cgen_Fatal(file, line, "CHECK_NE(%s, %s) failed\n#   Value: %p",
             expected_source, value_source, value);
  }
}


// Helper function used by the CHECK function when given floating
// point arguments.  Should not be called directly.
void CheckEqualsHelper(const char* file,
                                     int line,
                                     const char* expected_source,
                                     double expected,
                                     const char* value_source,
                                     double value) {
  // Force values to 64 bit memory to truncate 80 bit precision on IA32.
  volatile double* exp = new double[1];
  *exp = expected;
  volatile double* val = new double[1];
  *val = value;
  if (*exp != *val) {
    Cgen_Fatal(file, line,
             "CHECK_EQ(%s, %s) failed\n#   Expected: %f\n#   Found: %f",
             expected_source, value_source, *exp, *val);
  }
  delete[] exp;
  delete[] val;
}

